﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using PioneerBoilerplate.Model;
using PioneerBoilerplate.Model.Admin;
using PioneerBoilerplate.Model.Audits;
using PioneerBoilerplate.Model.BaseEntity;
using PioneerBoilerplate.Repository.Seed;
using PioneerBoilerplate.Util.Auth;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Yitter.IdGenerator;

namespace PioneerBoilerplate.Repository
{
    public class ApplicationDbContext : DbContext
    {
        private readonly AuditingInterceptor _auditingInterceptor = new AuditingInterceptor("Server=.;Database=PioneerBoilerplateDb;Trusted_Connection=True;MultipleActiveResultSets=true");
        public static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
        public readonly IUser _user;
        public readonly IServiceProvider _serviceProvider;
        public ApplicationDbContext(
            DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {

            IServiceCollection services = new ServiceCollection();
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.TryAddSingleton<IUser, User>();
            _serviceProvider = services.BuildServiceProvider();
            _user = _serviceProvider.GetService<IUser>();
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      => optionsBuilder.UseLoggerFactory(loggerFactory)
            .AddInterceptors(_auditingInterceptor);

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {

                if (typeof(IEntitySoftDelete).IsAssignableFrom(entityType.ClrType))
                {
                    entityType.AddSoftDeleteQueryFilter();
                }
            }

                DataSeeding data = new DataSeeding();
                modelBuilder.Entity<UserEntity>().HasData(data.Users);
                modelBuilder.Entity<RoleEntity>().HasData(data.Roles);
                //modelBuilder.Entity<UserRoleEntity>().HasData(data.UserRoles);
                modelBuilder.Entity<ViewEntity>().HasData(data.Views);
                modelBuilder.Entity<PermissionEntity>().HasData(data.Permissions);
                modelBuilder.Entity<ApiEntity>().HasData(data.Apis);
                modelBuilder.Entity<PermissionApiEntity>().HasData(data.PermissionApis);
                //modelBuilder.Entity<RolePermissionEntity>().HasData(data.RolePermissions);

                modelBuilder.Entity<DictionaryTypeEntity>().HasData(data.DictionaryTypes);
                modelBuilder.Entity<DictionaryEntity>().HasData(data.Dictionaries);
            
        }

        public override int SaveChanges()
        {
            ProcessEntityState();

            return base.SaveChanges();
        }

        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            ProcessEntityState();

            return await base.SaveChangesAsync(cancellationToken);
        }

        #region 审计实体
        private void ProcessEntityState()
        {
            //添加操作
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is Entity).ToList()
                 .ForEach(e => ((Entity)e.Entity).Id = YitIdHelper.NextId());

            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityAdd).ToList()
                .ForEach(e => ((EntityAdd)e.Entity).Id = YitIdHelper.NextId());
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityAdd).ToList()
                .ForEach(e => ((EntityAdd)e.Entity).CreatedTime = DateTime.Now);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityAdd).ToList()
                .ForEach(e => ((EntityAdd)e.Entity).CreatedUserId = _user?.Id);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityAdd).ToList()
                .ForEach(e => ((EntityAdd)e.Entity).CreatedUserName = _user?.Name);

            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityFull).ToList()
               .ForEach(e => ((EntityFull)e.Entity).Id = YitIdHelper.NextId());
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityFull).ToList()
               .ForEach(e => ((EntityFull)e.Entity).CreatedTime = DateTime.Now);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityFull).ToList()
               .ForEach(e => ((EntityFull)e.Entity).CreatedUserId = _user?.Id);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is EntityFull).ToList()
               .ForEach(e => ((EntityFull)e.Entity).CreatedUserName = _user?.Name);


            //修改操作
            ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is EntityFull).ToList()
                .ForEach(e => ((EntityFull)e.Entity).ModifiedTime = DateTime.Now);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is EntityFull).ToList()
                .ForEach(e => ((EntityFull)e.Entity).ModifiedUserId = _user?.Id);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is EntityFull).ToList()
                .ForEach(e => ((EntityFull)e.Entity).ModifiedUserName = _user?.Name);

            ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is EntityUpdate).ToList()
                .ForEach(e => ((EntityUpdate)e.Entity).ModifiedTime = DateTime.Now);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is EntityUpdate).ToList()
                .ForEach(e => ((EntityUpdate)e.Entity).ModifiedUserId = _user?.Id);
            ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is EntityUpdate).ToList()
                .ForEach(e => ((EntityUpdate)e.Entity).ModifiedUserName = _user?.Name);
        }
        #endregion

        #region 数据库相关表
        public DbSet<Book> Books { get; set; }
        public DbSet<ApiEntity> Apis { get; set; }
        public DbSet<DictionaryEntity> Dictionaries { get; set; }
        public DbSet<DictionaryTypeEntity> DictionariesTypes { get; set; }
        public DbSet<DocumentEntity> Documents { get; set; }
        public DbSet<DocumentImageEntity> DocumentImages { get; set; }
        public DbSet<LoginLogEntity> LoginLogs { get; set; }
        public DbSet<OprationLogEntity> OprationLogs { get; set; }
        public DbSet<PermissionEntity> Permissions { get; set; }
        public DbSet<PermissionApiEntity> PermissionApis { get; set; }
        public DbSet<RoleEntity> Roles { get; set; }
        public DbSet<RolePermissionEntity> RolePermissions { get; set; }
        public DbSet<UserEntity> Users { get; set; }
        public DbSet<UserRoleEntity> UserRoles { get; set; }
        public DbSet<ViewEntity> Views { get; set; }
        public DbSet<SaveChangesAuditEntity> SaveChangesAudits { get; set; }
        public DbSet<AuditEntity> Audits { get; set; }
        #endregion
    }
}
